home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / shadow-3.1.4 / groupio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-26  |  10.8 KB  |  592 lines

  1. /*
  2.  * Copyright 1990, 1991, John F. Haugh II
  3.  * All rights reserved.
  4.  *
  5.  * Permission is granted to copy and create derivative works for any
  6.  * non-commercial purpose, provided this copyright notice is preserved
  7.  * in all copies of source code, or included in human readable form
  8.  * and conspicuously displayed on all copies of object code or
  9.  * distribution media.
  10.  *
  11.  *    This file implements a transaction oriented group database
  12.  *    library.  The group file is updated one entry at a time.
  13.  *    After each transaction the file must be logically closed and
  14.  *    transferred to the existing group file.  The sequence of
  15.  *    events is
  16.  *
  17.  *    gr_lock                -- lock group file
  18.  *    gr_open                -- logically open group file
  19.  *    while transaction to process
  20.  *        gr_(locate,update,remove) -- perform transaction
  21.  *    done
  22.  *    gr_close            -- commit transactions
  23.  *    gr_unlock            -- remove group lock
  24.  */
  25.  
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <fcntl.h>
  29. #include <errno.h>
  30. #include <grp.h>
  31. #include <stdio.h>
  32. #ifdef    BSD
  33. #include <strings.h>
  34. #else
  35. #include <string.h>
  36. #endif
  37.  
  38. #ifndef    lint
  39. static    char    sccsid[] = "@(#)groupio.c    3.9 08:45:35 9/12/91";
  40. #endif
  41.  
  42. static    int    islocked;
  43. static    int    isopen;
  44. static    int    open_modes;
  45. static    FILE    *grfp;
  46.  
  47. struct    gr_file_entry {
  48.     char    *grf_line;
  49.     int    grf_changed;
  50.     struct    group    *grf_entry;
  51.     struct    gr_file_entry *grf_next;
  52. };
  53.  
  54. static    struct    gr_file_entry    *grf_head;
  55. static    struct    gr_file_entry    *grf_tail;
  56. static    struct    gr_file_entry    *grf_cursor;
  57. static    int    gr_changed;
  58. static    int    lock_pid;
  59.  
  60. #define    GR_LOCK    "/etc/group.lock"
  61. #define    GR_TEMP "/etc/grp.%d"
  62. #define    GROUP    "/etc/group"
  63.  
  64. static    char    gr_filename[BUFSIZ] = GROUP;
  65.  
  66. extern    char    *strdup();
  67. extern    struct    group    *sgetgrent();
  68. extern    char    *malloc();
  69. extern    char    *fgetsx();
  70.  
  71. /*
  72.  * gr_dup - duplicate a group file entry
  73.  *
  74.  *    gr_dup() accepts a pointer to a group file entry and
  75.  *    returns a pointer to a group file entry in allocated
  76.  *    memory.
  77.  */
  78.  
  79. static struct group *
  80. gr_dup (grent)
  81. struct    group    *grent;
  82. {
  83.     struct    group    *gr;
  84.     int    i;
  85.  
  86.     if (! (gr = (struct group *) malloc (sizeof *gr)))
  87.         return 0;
  88.  
  89.     if ((gr->gr_name = strdup (grent->gr_name)) == 0 ||
  90.             (gr->gr_passwd = strdup (grent->gr_passwd)) == 0)
  91.         return 0;
  92.  
  93.     for (i = 0;grent->gr_mem[i];i++)
  94.         ;
  95.  
  96.     gr->gr_mem = (char **) malloc (sizeof (char *) * (i + 1));
  97.     for (i = 0;grent->gr_mem[i];i++)
  98.         if (! (gr->gr_mem[i] = strdup (grent->gr_mem[i])))
  99.             return 0;
  100.  
  101.     gr->gr_mem[i] = 0;
  102.     gr->gr_gid = grent->gr_gid;
  103.  
  104.     return gr;
  105. }
  106.  
  107. /*
  108.  * gr_free - free a dynamically allocated group file entry
  109.  *
  110.  *    gr_free() frees up the memory which was allocated for the
  111.  *    pointed to entry.
  112.  */
  113.  
  114. static void
  115. gr_free (grent)
  116. struct    group    *grent;
  117. {
  118.     int    i;
  119.  
  120.     free (grent->gr_name);
  121.     free (grent->gr_passwd);
  122.  
  123.     for (i = 0;grent->gr_mem[i];i++)
  124.         free (grent->gr_mem[i]);
  125.  
  126.     free ((char *) grent->gr_mem);
  127. }
  128.  
  129. /*
  130.  * gr_name - change the name of the group file
  131.  */
  132.  
  133. int
  134. gr_name (name)
  135. char    *name;
  136. {
  137.     if (isopen || strlen (name) > (BUFSIZ-10))
  138.         return -1;
  139.  
  140.     strcpy (gr_filename, name);
  141.     return 0;
  142. }
  143.  
  144. /*
  145.  * gr_lock - lock a group file
  146.  *
  147.  *    gr_lock() encapsulates the lock operation.  it returns
  148.  *    TRUE or FALSE depending on the group file being
  149.  *    properly locked.  the lock is set by creating a semaphore
  150.  *    file, GR_LOCK.
  151.  */
  152.  
  153. int
  154. gr_lock ()
  155. {
  156.     int    fd;
  157.     int    pid;
  158.     int    len;
  159.     char    file[BUFSIZ];
  160.     char    buf[32];
  161.     struct    stat    sb;
  162.  
  163.     if (islocked)
  164.         return 1;
  165.  
  166.     if (strcmp (gr_filename, GROUP) != 0)
  167.         return 0;
  168.  
  169.     /*
  170.      * Create a lock file which can be switched into place
  171.      */
  172.  
  173.     sprintf (file, GR_TEMP, lock_pid = getpid ());
  174.     if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
  175.         return 0;
  176.  
  177.     sprintf (buf, "%d", lock_pid);
  178.     if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
  179.         (void) close (fd);
  180.         (void) unlink (file);
  181.         return 0;
  182.     }
  183.     close (fd);
  184.  
  185.     /*
  186.      * Simple case first -
  187.      *    Link fails (in a sane environment ...) if the target
  188.      *    exists already.  So we try to switch in a new lock
  189.      *    file.  If that succeeds, we assume we have the only
  190.      *    valid lock.  Needs work for NFS where this assumption
  191.      *    may not hold.  The simple hack is to check the link
  192.      *    count on the source file, which should be 2 iff the
  193.      *    link =really= worked.
  194.      */
  195.  
  196.     if (link (file, GR_LOCK) == 0) {
  197.         if (stat (file, &sb) != 0)
  198.             return 0;
  199.  
  200.         if (sb.st_nlink != 2)
  201.             return 0;
  202.  
  203.         (void) unlink (file);
  204.         islocked = 1;
  205.         return 1;
  206.     }
  207.  
  208.     /*
  209.      * Invalid lock test -
  210.      *    Open the lock file and see if the lock is valid.
  211.      *    The PID of the lock file is checked, and if the PID
  212.      *    is not valid, the lock file is removed.  If the unlink
  213.      *    of the lock file fails, it should mean that someone
  214.      *    else is executing this code.  They will get success,
  215.      *    and we will fail.
  216.      */
  217.  
  218.     if ((fd = open (GR_LOCK, O_RDWR)) == -1 ||
  219.             (len = read (fd, buf, BUFSIZ)) <= 0) {
  220.         errno = EINVAL;
  221.         return 0;
  222.     }
  223.     buf[len] = '\0';
  224.     if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
  225.         errno = EINVAL;
  226.         return 0;
  227.     }
  228.     if (kill (pid, 0) == 0)  {
  229.         errno = EEXIST;
  230.         return 0;
  231.     }
  232.     if (unlink (GR_LOCK)) {
  233.         (void) close (fd);
  234.         (void) unlink (file);
  235.  
  236.         return 0;
  237.     }
  238.  
  239.     /*
  240.      * Re-try lock -
  241.      *    The invalid lock has now been removed and I should
  242.      *    be able to acquire a lock for myself just fine.  If
  243.      *    this fails there will be no retry.  The link count
  244.      *    test here makes certain someone executing the previous
  245.      *    block of code didn't just remove the lock we just
  246.      *    linked to.
  247.      */
  248.  
  249.     if (link (file, GR_LOCK) == 0) {
  250.         if (stat (file, &sb) != 0)
  251.             return 0;
  252.  
  253.         if (sb.st_nlink != 2)
  254.             return 0;
  255.  
  256.         (void) unlink (file);
  257.         islocked = 1;
  258.         return 1;
  259.     }
  260.     (void) unlink (file);
  261.     return 0;
  262. }
  263.  
  264. /*
  265.  * gr_unlock - logically unlock a group file
  266.  *
  267.  *    gr_unlock() removes the lock which was set by an earlier
  268.  *    invocation of gr_lock().
  269.  */
  270.  
  271. int
  272. gr_unlock ()
  273. {
  274.     if (isopen) {
  275.         open_modes = O_RDONLY;
  276.         if (! gr_close ())
  277.             return 0;
  278.     }
  279.     if (islocked) {
  280.         islocked = 0;
  281.         if (lock_pid != getpid ())
  282.             return 0;
  283.  
  284.         (void) unlink (GR_LOCK);
  285.         return 1;
  286.     }
  287.     return 0;
  288. }
  289.  
  290. /*
  291.  * gr_open - open a group file
  292.  *
  293.  *    gr_open() encapsulates the open operation.  it returns
  294.  *    TRUE or FALSE depending on the group file being
  295.  *    properly opened.
  296.  */
  297.  
  298. int
  299. gr_open (mode)
  300. int    mode;
  301. {
  302.     char    buf[8192];
  303.     char    *cp;
  304.     struct    gr_file_entry    *grf;
  305.     struct    group    *grent;
  306.  
  307.     if (isopen || (mode != O_RDONLY && mode != O_RDWR))
  308.         return 0;
  309.  
  310.     if (mode != O_RDONLY && ! islocked &&
  311.             strcmp (gr_filename, GROUP) == 0)
  312.         return 0;
  313.  
  314.     if ((grfp = fopen (gr_filename, mode == O_RDONLY ? "r":"r+")) == 0)
  315.         return 0;
  316.  
  317.     grf_head = grf_tail = grf_cursor = 0;
  318.     gr_changed = 0;
  319.  
  320.     while (fgetsx (buf, sizeof buf, grfp) != (char *) 0) {
  321.         if (cp = strrchr (buf, '\n'))
  322.             *cp = '\0';
  323.  
  324.         if (! (grf = (struct gr_file_entry *) malloc (sizeof *grf)))
  325.             return 0;
  326.  
  327.         grf->grf_changed = 0;
  328.         grf->grf_line = strdup (buf);
  329.         if ((grent = sgetgrent (buf)) && ! (grent = gr_dup (grent)))
  330.             return 0;
  331.  
  332.         grf->grf_entry = grent;
  333.  
  334.         if (grf_head == 0) {
  335.             grf_head = grf_tail = grf;
  336.             grf->grf_next = 0;
  337.         } else {
  338.             grf_tail->grf_next = grf;
  339.             grf->grf_next = 0;
  340.             grf_tail = grf;
  341.         }
  342.     }
  343.     isopen++;
  344.     open_modes = mode;
  345.  
  346.     return 1;
  347. }
  348.  
  349. /*
  350.  * gr_close - close the group file
  351.  *
  352.  *    gr_close() outputs any modified group file entries and
  353.  *    frees any allocated memory.
  354.  */
  355.  
  356. int
  357. gr_close ()
  358. {
  359.     char    backup[BUFSIZ];
  360.     int    mask;
  361.     int    c;
  362.     int    errors = 0;
  363.     FILE    *bkfp;
  364.     struct    gr_file_entry *grf;
  365.     struct    stat    sb;
  366.  
  367.     if (! isopen) {
  368.         errno = EINVAL;
  369.         return 0;
  370.     }
  371.     if (islocked && lock_pid != getpid ()) {
  372.         isopen = 0;
  373.         islocked = 0;
  374.         errno = EACCES;
  375.         return 0;
  376.     }
  377.     strcpy (backup, gr_filename);
  378.     strcat (backup, "-");
  379.  
  380.     if (open_modes == O_RDWR && gr_changed) {
  381.         mask = umask (0222);
  382.         if ((bkfp = fopen (backup, "w")) == 0) {
  383.             umask (mask);
  384.             return 0;
  385.         }
  386.         umask (mask);
  387.         fstat (fileno (grfp), &sb);
  388.         chown (backup, sb.st_uid, sb.st_gid);
  389.  
  390.         rewind (grfp);
  391.         while ((c = getc (grfp)) != EOF) {
  392.             if (putc (c, bkfp) == EOF) {
  393.                 fclose (bkfp);
  394.                 return 0;
  395.             }
  396.         }
  397.         if (fclose (bkfp))
  398.             return 0;
  399.  
  400.         isopen = 0;
  401.         (void) fclose (grfp);
  402.  
  403.         mask = umask (0222);
  404.         if (! (grfp = fopen (gr_filename, "w"))) {
  405.             umask (mask);
  406.             return 0;
  407.         }
  408.         umask (mask);
  409.  
  410.         for (grf = grf_head;! errors && grf;grf = grf->grf_next) {
  411.             if (grf->grf_changed) {
  412.                 if (putgrent (grf->grf_entry, grfp))
  413.                     errors++;
  414.             } else {
  415.                 if (fputsx (grf->grf_line, grfp))
  416.                     errors++;
  417.  
  418.                 if (putc ('\n', grfp) == EOF)
  419.                     errors++;
  420.             }
  421.         }
  422.         if (fflush (grfp))
  423.             errors++;
  424.  
  425.         if (errors) {
  426.             unlink (gr_filename);
  427.             link (backup, gr_filename);
  428.             unlink (backup);
  429.             return 0;
  430.         }
  431.     }
  432.     if (fclose (grfp))
  433.         return 0;
  434.  
  435.     grfp = 0;
  436.  
  437.     while (grf_head != 0) {
  438.         grf = grf_head;
  439.         grf_head = grf->grf_next;
  440.  
  441.         if (grf->grf_entry) {
  442.             gr_free (grf->grf_entry);
  443.             free ((char *) grf->grf_entry);
  444.         }
  445.         if (grf->grf_line)
  446.             free (grf->grf_line);
  447.  
  448.         free ((char *) grf);
  449.     }
  450.     grf_tail = 0;
  451.     isopen = 0;
  452.     return 1;
  453. }
  454.  
  455. int
  456. gr_update (grent)
  457. struct    group    *grent;
  458. {
  459.     struct    gr_file_entry    *grf;
  460.     struct    group    *ngr;
  461.  
  462.     if (! isopen || open_modes == O_RDONLY) {
  463.         errno = EINVAL;
  464.         return 0;
  465.     }
  466.     for (grf = grf_head;grf != 0;grf = grf->grf_next) {
  467.         if (grf->grf_entry == 0)
  468.             continue;
  469.  
  470.         if (strcmp (grent->gr_name, grf->grf_entry->gr_name) != 0)
  471.             continue;
  472.  
  473.         if (! (ngr = gr_dup (grent)))
  474.             return 0;
  475.         else {
  476.             gr_free (grf->grf_entry);
  477.             *(grf->grf_entry) = *ngr;
  478.         }
  479.         grf->grf_changed = 1;
  480.         grf_cursor = grf;
  481.         return gr_changed = 1;
  482.     }
  483.     grf = (struct gr_file_entry *) malloc (sizeof *grf);
  484.     if (! (grf->grf_entry = gr_dup (grent)))
  485.         return 0;
  486.  
  487.     grf->grf_changed = 1;
  488.     grf->grf_next = 0;
  489.     grf->grf_line = 0;
  490.  
  491.     if (grf_tail)
  492.         grf_tail->grf_next = grf;
  493.  
  494.     if (! grf_head)
  495.         grf_head = grf;
  496.  
  497.     grf_tail = grf;
  498.  
  499.     return gr_changed = 1;
  500. }
  501.  
  502. int
  503. gr_remove (name)
  504. char    *name;
  505. {
  506.     struct    gr_file_entry    *grf;
  507.     struct    gr_file_entry    *ogrf;
  508.  
  509.     if (! isopen || open_modes == O_RDONLY) {
  510.         errno = EINVAL;
  511.         return 0;
  512.     }
  513.     for (ogrf = 0, grf = grf_head;grf != 0;
  514.             ogrf = grf, grf = grf->grf_next) {
  515.         if (! grf->grf_entry)
  516.             continue;
  517.  
  518.         if (strcmp (name, grf->grf_entry->gr_name) != 0)
  519.             continue;
  520.  
  521.         if (grf == grf_cursor)
  522.             grf_cursor = ogrf;
  523.  
  524.         if (ogrf != 0)
  525.             ogrf->grf_next = grf->grf_next;
  526.         else
  527.             grf_head = grf->grf_next;
  528.  
  529.         if (grf == grf_tail)
  530.             grf_tail = ogrf;
  531.  
  532.         return gr_changed = 1;
  533.     }
  534.     errno = ENOENT;
  535.     return 0;
  536. }
  537.  
  538. struct group *
  539. gr_locate (name)
  540. char    *name;
  541. {
  542.     struct    gr_file_entry    *grf;
  543.  
  544.     if (! isopen) {
  545.         errno = EINVAL;
  546.         return 0;
  547.     }
  548.     for (grf = grf_head;grf != 0;grf = grf->grf_next) {
  549.         if (grf->grf_entry == 0)
  550.             continue;
  551.  
  552.         if (strcmp (name, grf->grf_entry->gr_name) == 0) {
  553.             grf_cursor = grf;
  554.             return grf->grf_entry;
  555.         }
  556.     }
  557.     errno = ENOENT;
  558.     return 0;
  559. }
  560.  
  561. int
  562. gr_rewind ()
  563. {
  564.     if (! isopen) {
  565.         errno = EINVAL;
  566.         return 0;
  567.     }
  568.     grf_cursor = 0;
  569.     return 1;
  570. }
  571.  
  572. struct group *
  573. gr_next ()
  574. {
  575.     if (! isopen) {
  576.         errno = EINVAL;
  577.         return 0;
  578.     }
  579.     if (grf_cursor == 0)
  580.         grf_cursor = grf_head;
  581.     else
  582.         grf_cursor = grf_cursor->grf_next;
  583.  
  584.     while (grf_cursor) {
  585.         if (grf_cursor->grf_entry)
  586.             return grf_cursor->grf_entry;
  587.  
  588.         grf_cursor = grf_cursor->grf_next;
  589.     }
  590.     return 0;
  591. }
  592.